package com.fansl.allround.daemon.quartz.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fansl.allround.common.core.util.SpringContextHolder;
import com.fansl.allround.daemon.quartz.config.ScheduleConstants;
import com.fansl.allround.daemon.quartz.entity.ScheduleJob;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author fansl
 * @Description: 任务执行工具
 * @date 2020/1/11 14:31
 */
public class JobInvokeUtil {
    public static void invokeMethod(ScheduleJob scheduleJob) throws Exception {
        String beanName = scheduleJob.getJobName();
        String methodName = scheduleJob.getMethodName();
        String methodParams = scheduleJob.getMethodParams();
        if (!isValidClassName(beanName)) {
            Object bean = SpringContextHolder.getBean(beanName);
            invokeMethod(bean, methodName, methodParams);
        } else {
            Object bean = Class.forName(beanName).newInstance();
            invokeMethod(bean, methodName, methodParams);
        }
    }

    /**
     * 调用任务方法
     *
     * @param bean         目标对象
     * @param methodName   方法名称
     * @param methodParams 方法参数
     */
    private static void invokeMethod(Object bean, String methodName, String methodParams)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        if (StrUtil.isNotBlank(methodParams)) {
            List<Map> params = JSONArray.parseArray(methodParams, Map.class);
            List<String> methodParamTypes = new ArrayList<>();
            params.stream().forEach(param -> {
                methodParamTypes.add(param.get(ScheduleConstants.METHOD_PARAM_TYPE_NAME).toString());
            });
            Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParamTypes));
            method.invoke(bean, getMethodParamsValue(params));
        } else {
            Method method = bean.getClass().getDeclaredMethod(methodName);
            method.invoke(bean);
        }
    }

    public static boolean isValidClassName(String invokeTarget) {
        return StrUtil.count(invokeTarget, ".") > 1;
    }

    /**
     * 获取参数类型
     *
     * @param methodParamTypes 参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<String> methodParamTypes) {
        Class<?>[] classs = new Class<?>[methodParamTypes.size()];
        int index = 0;
        for (String type : methodParamTypes) {
            try {
                classs[index] = Class.forName(type);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            index++;
        }
        return classs;
    }

    /**
     * 获取参数值
     *
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Map> methodParams) {
        Object[] objects = new Object[methodParams.size()];
        int index = 0;
        for (Map methodParamMap : methodParams) {
            String valueType = methodParamMap.get(ScheduleConstants.METHOD_PARAM_TYPE_NAME).toString();
            String value = methodParamMap.get(ScheduleConstants.METHOD_PARAM_VALUE).toString();

            try {
                Class<?> clazz = Class.forName(valueType);
                if ("java.lang.String".equals(clazz.getCanonicalName())) {
                    objects[index] = value;
                } else if ("java.lang.Integer".equals(clazz.getCanonicalName())) {
                    objects[index] = Integer.parseInt(value);
                } else if ("java.lang.Long".equals(clazz.getCanonicalName())) {
                    objects[index] = Long.parseLong(value);
                } else if ("java.lang.Boolean".equals(clazz.getCanonicalName())) {
                    objects[index] = Boolean.parseBoolean(value);
                } else {
                    objects[index] = JSONObject.parseObject(value, clazz);
                }

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            index++;
        }
        return objects;
    }
}
